﻿using UnityEngine;
using UnityEditor;
using System;
using HDJ.Framework.Core;
using System.Reflection;
using System.Collections.Generic;

public class C_SharpModule2JavaCodeEditorWindow : EditorWindow
{


    [MenuItem("Tool/工具/C# Model 转换成 Java代码(Json转换使用)")]
    static void DoIt()
    {
        GetWindow<C_SharpModule2JavaCodeEditorWindow>();
    }
    Type type = null;
    private string typeName;
    private static string outPutPath = "";
    private void OnEnable()
    {
        outPutPath = Application.dataPath.Replace("Assets", "") + "C_SharpModule2JavaCode/";
    }
    private void OnGUI()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("Type Name");
        typeName = EditorGUILayout.TextArea(typeName);
        GUILayout.EndHorizontal();
        Vector2 p = new Vector2();
        p[0] = 1;
        bool canChange = false;
        if (!string.IsNullOrEmpty(typeName))
        {
            type = ReflectionUtils.GetTypeByTypeFullName(typeName);
            if (type != null && CheckNeedChangeType(type))
            {
                canChange = true;

                GUI.color = Color.green;
                GUILayout.Label("Find Type ：" + type.FullName);
                GUI.color = Color.white;
            }
        }
        if (canChange)
        {
            EditorDrawGUIUtil.DrawScrollView(allNeedChangeType, () =>
             {
                 allNeedChangeType.Clear();
                 allNeedChangeType.Add(type);
                 GetNeedChangeJavaType(type);
                 GUILayout.BeginVertical("box");
                 GUILayout.Box("Can Change Type :");
                 foreach (var item in allNeedChangeType)
                 {
                     EditorGUILayout.SelectableLabel("Type :" + item.FullName);
                 }
                 GUILayout.EndVertical();
             });
           
        }
        GUILayout.FlexibleSpace();
        GUILayout.Label("OutPutPath :" + outPutPath);
        GUILayout.Space(4);
        if (canChange && GUILayout.Button("Change"))
        {

            foreach (var item in allNeedChangeType)
            {
                string ss = Change2JavaCode(item);
                FileUtils.CreateTextFile(outPutPath + item.Name + ".java", ss);
            }

            EditorUtility.DisplayDialog("", "Successful", "OK");
        }
    }

    private string Change2JavaCode(Type type)
    {

        string code = "\n";
        code += "public";
        code += " ";
        if (type.IsEnum)
            code += "enum";
        else if (type.IsClass || type.IsValueType)
            code += "class";
        code += " ";
        code += type.Name;
        code += "\n";
        code += "{\n";
        if (type.IsEnum)
        {
            
            string[] nameEnums = Enum.GetNames(type);
            foreach (var item in nameEnums)
            {
                code += "\t " + item + ",\n";
            }
        }
        else
        {
            FieldInfo[] fs = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
            foreach (var f in fs)
            {
                code += CreateJavaFieldString(f);
            }
            //PropertyInfo[] ps = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
            //foreach (var p in ps)
            //{
            //    if (p.CanRead && p.CanWrite)
            //        code += CreateJavaFieldString(p.PropertyType, p.Name);
            //}
        }
        code += "}\n";

        return code;
    }

    private string CreateJavaFieldString(FieldInfo f)
    {
        Type type = f.FieldType;
        string name = f.Name;

        string code = "\tpublic";
        code += " ";

        if (f.IsStatic)
        {
            code += "static ";
        }
        if (f.IsLiteral)
        {
            code += "final ";
        }

        code += GetJavaTypeString(type);


        code += " ";
        code += name;
        if (f.IsStatic || f.IsLiteral)
        {
            code +=" = "+ GetConstantValue(f);
        }
            code += ";\n";

        if (!f.IsStatic && !f.IsLiteral)
        {
            //set
            code += "\tpublic";
            code += " ";
            code += "void";
            code += " ";
            code += "set" + name[0].ToString().ToUpper() + name.Remove(0, 1) + "(" + GetJavaTypeString(type) + " " + name + ")";
            code += "\n";
            code += "\t {";
            code += "\n";
            code += "\t\t this." + name + " = " + name + ";";
            code += "\n";
            code += "\t }\n";

            //get
            code += "\tpublic";
            code += " ";
            code += GetJavaTypeString(type);
            code += " ";
            code += "get" + name[0].ToString().ToUpper() + name.Remove(0, 1) + "()";
            code += "\n";
            code += "\t {";
            code += "\n";
            code += "\t\t return " + name + ";";
            code += "\n";
            code += "\t }\n";
        }
        return code;
    }

    private string GetConstantValue(FieldInfo f)
    {
        Type type = f.FieldType;
        string code = "";
        object value = f.GetValue(null);
        Debug.Log("GetConstantValue :" + value);
        if (value != null)
        {
            if (type == typeof(float))
                code +=  value.ToString()+"f";
            else if (type == typeof(byte))
                code += value.ToString();
            else if (type == typeof(char))
                code += "'"+value.ToString()+"'";
            else if (type == typeof(double))
                code += value.ToString()+"d";
            else if (type == typeof(int))
                code += value.ToString();
            else if (type == typeof(long))
                code += value.ToString()+"L";
            else if (type == typeof(short))
                code += value.ToString();
            else if (type == typeof(bool))
                code += value.ToString();
            else if (type == typeof(string))
                code += "\"" + value.ToString() + "\"";
            else if (type.IsEnum)
            {
                code += type.Name + "." + value.ToString();
            }
        }
        return code;
    }

    private string GetJavaTypeString(Type type)
    {
        string code = "";
        if (type == typeof(float))
            code += "float";
        else if (type == typeof(object))
            code += "Object";
        else if (type == typeof(byte))
            code += "byte";
        else if (type == typeof(char))
            code += "char";
        else if (type == typeof(double))
            code += "double";
        else if (type == typeof(int))
            code += "Integer";
        else if (type == typeof(long))
            code += "long";
        else if (type == typeof(short))
            code += "short";
        else if (type == typeof(bool))
            code += "boolean";
        else if (type.Name == typeof(List<>).Name)
        {
            code += "ArrayList<";
            Type[] gArr = type.GetGenericArguments();

            code += GetJavaTypeString(gArr[0]) + ">";
        }
        else if (type.Name == typeof(Dictionary<,>).Name)
        {
            code += "HashMap<";
            Type[] gArr = type.GetGenericArguments();

            code += GetJavaTypeString(gArr[0]) + "," + GetJavaTypeString(gArr[1]) + ">";
        }
        else if (type.IsArray)
        {

            code += GetJavaTypeString(type.GetElementType()) + "[]";
        }
        else
            code += type.Name;

        return code;
    }

    private List<Type> allNeedChangeType = new List<Type>();
    private void GetNeedChangeJavaType(Type type)
    {
        if (!CheckNeedChangeType(type))
            return;

        FieldInfo[] fs = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
        foreach (var f in fs)
        {
            GetDetailTypeCheck(f.FieldType);
        }
        PropertyInfo[] ps = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
        foreach (var p in ps)
        {
            if (p.CanRead && p.CanWrite)
                GetDetailTypeCheck(p.PropertyType);
        }
    }

    private void GetDetailTypeCheck(Type type)
    {
        if (type.IsGenericType)
        {
            if (type.Name == typeof(List<>).Name)
            {
                Type tempT = type.GetGenericArguments()[0];
                GetDetailTypeCheck(tempT);
                GetNeedChangeJavaType(tempT);
            }
            else if (type.Name == typeof(Dictionary<,>).Name)
            {
                Type[] tempT = type.GetGenericArguments();
                GetDetailTypeCheck(tempT[0]);
                GetNeedChangeJavaType(tempT[0]);
                GetDetailTypeCheck(tempT[1]);
                GetNeedChangeJavaType(tempT[1]);
            }
        }
        else if (type.IsArray)
        {
            Type tempT = type.GetElementType();
            GetNeedChangeJavaType(tempT);
        }
        else if (type.IsPrimitive || type == typeof(string))
            return;
        else
        {
            if (!allNeedChangeType.Contains(type))
                allNeedChangeType.Add(type);
            if (type.IsClass || type.IsValueType)
                GetNeedChangeJavaType(type);
        }
    }
    private bool CheckNeedChangeType(Type type)
    {
        if (type.IsPrimitive || type == typeof(string) || type.IsGenericType)
            return false;

        return true;
    }
}